<?php
require_once 'Zend/Gdata/Calendar.php';
require_once 'Zend/Gdata/ClientLogin.php';
require_once dirname(__FILE__) . '/../DateMath.php';

class Google_Calender
{
	const KEY_EVENT_ID = 'ID';
	const KEY_EVENT_NAME = 'NAME';
	const KEY_EVENT_START_TIME = 'START_TIME';
	const KEY_EVENT_END_TIME = 'END_TIME';
	const KEY_EVENT_ALLDAY = 'ALLDAY';
	const KEY_EVENT_UPDATED = 'UPDATED';
	const KEY_EVENT_CONTENT = 'CONTENT';
	/** サービスインスタンス */
	protected $_service;
	/** カレンダーリストインスタンス*/
	protected $_calendarList = array();
	/** イベントフィードインスタンス */
	protected $_eventFeed = array();
	/** イベント数 */
	protected $_eventCount = 0;
	/** ターゲットイベント　*/
	protected $_targetEvent=FALSE;
	/** カレンダーユーザ（登録カレンダーのUID） */
	protected $_user = 'default';
	/** 例外エラーメッセージ */
	public $exceptionErrorMessage;

	/**
	 * コンストラクタ
	 * @param unknown $user
	 * @param unknown $pass
	 */
	public function __construct($user, $pass)
	{
		// action body
		$service = Zend_Gdata_Calendar::AUTH_SERVICE_NAME;
		$this->exceptionErrorMessage = '';

		// 認証済みの HTTP クライアントを作成します
		try {
			$client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $service);
		} catch (Zend_Gdata_App_AuthException $ae) {
			$this->exceptionErrorMessage = $ae->getMessage();
			return;
		}
		// Calendar サービスのインスタンスを作成します
		$service = new Zend_Gdata_Calendar($client);
		$this->_service = $service;
	}

	public function イベントを追加する(
			$title,
			$content,
			$startDateTime,
			$endDateTime=''
	)
	{
		return $this->addEvent($title, $content, $startDateTime,$endDateTime);
	}
	const デフォルト期間  = 3600; // 一時間
	/**
	 * イベントを追加する
	 * @param unknown $title
	 * @param unknown $content
	 * @param unknown $startDateTime	YYYY-MM-DD HH:SS
	 * @param unknown $endDateTime		YYYY-MM-DD HH:SS
	 * @param unknown $allDay			BOOLEAN
	 */
	public function addEvent(
		$title,
		$content,
		$startDateTime,
		$endDateTime=''
	)
	{
		/*ANALYZER*/$this->_outAnalyzer('start AddEvent METHOD');
		if ($endDateTime == '') {
			$dateTime = strtotime($startDateTime) + self::デフォルト期間;
			$endDateTime = date('Y-m-d H:00', $dateTime);
		}
		$postUri = "http://www.google.com/calendar/feeds/" . $this->_user . "/private/full";
		$gdataCal = $this->_service;
		$event= $gdataCal->newEventEntry();
		$event->title = $gdataCal->newTitle($title);
		$event->content = $gdataCal->newContent($content);
		$when = $this->_createWhen($startDateTime,$endDateTime);
		$event->when = array($when);
		$newEvent = $gdataCal->insertEvent($event,$postUri);
		/*ANALYZER*/$this->_outAnalyzer(print_r($event,true));
		return $newEvent->id;
	}

	/**
	 * イベントに設定する開始終了日時オブジェクトを生成する
	 * @param unknown $startDateTime YYYY-MM-DD HH:SS
	 * @param string $endDateTime    YYYY-MM-DD HH:SS
	 * @return unknown
	 */
	protected function _createWhen(
			$startDateTime,
			$endDateTime=''
	){
		$this->_createStartDateTimeEndDateTime($startDate, $startTime, $endDate, $endTime, $allDayFlg, $startDateTime, $endDateTime);
		$when = $this->_service->newWhen();
		$tzOffset = "+09";
		if ($allDayFlg == TRUE) {
			$when->startTime = "{$startDate}";
			$when->endTime = "{$endDate}";
		} else {
			$when->startTime = "{$startDate}T{$startTime}:00.000{$tzOffset}:00";
			$when->endTime = "{$endDate}T{$endTime}:00.000{$tzOffset}:00";
		}
		return $when;
	}

	/**
	 * 開始日時（$startDateTime)、終了日時（$endDateTime)
	 * を、日付と時刻に分離。さらに時刻が無ければ終日フラグを設定
	 * @param unknown $startDate
	 * @param unknown $startTime
	 * @param unknown $endDate
	 * @param unknown $endTime
	 * @param unknown $allDayFlg
	 * @param unknown $startDateTime
	 * @param string $endDateTime
	 * @return boolean
	 */
	protected function _createStartDateTimeEndDateTime(
			&$startDate,
			&$startTime,
			&$endDate,
			&$endTime,
			&$allDayFlg,
			$startDateTime,
			$endDateTime=''
	){
		if (!self::validDateTime($startDateTime)) {
			return FALSE;
		}
		if ($endDateTime != '') {
			if (!self::validDateTime($endDateTime)) {
				return FALSE;
			}
		}
		$allDayFlg = FALSE;
		/*** 開始と終了が同じ日時の場合は登録しない */
		if ($startDateTime == $endDateTime) {
			return FALSE;
		}
		/*** 終日判定 */
		if (strlen($startDateTime) == strlen('YYYY-MM-DD')) {
			$allDayFlg = TRUE;
			$startDate = $startDateTime;
			/*** 翌日作成 */
			$baseDate = str_replace('-', '', $startDate).'0000';
			$objDateMath = new DateMath($baseDate);
			$objDateMath->getDateAfterDays(1);
			$endDate = ''
					. $objDateMath->iResultYear
					. '-'
							. $objDateMath->iResultMonth
							. '-'
									. $objDateMath->iResultDay;
		}

		/*** 開始終了時刻初期化 */
		$startTime = '00:00';
		$endTime = '01:00';

		/*** 日／時分割 */
		if (!$allDayFlg) {
			$divide = explode(' ', $startDateTime);
			$startDate = $divide[0];
			$startTime = $divide[1];
			$divide = explode(' ', $endDateTime);
			$endDate = $divide[0];
			$endTime = $divide[1];
		}
		return TRUE;
	}

	public function 編集イベントを設定する($eventId)
	{
		return $this->setTargetEvent($eventId);
	}
	/**
	 * 編集イベントを設定する
	 * @param $eventId
	 */
	public function setTargetEvent($eventId)
	{
		$this->_targetEvent = $this->getEventFromId($eventId);
		return $this->_targetEvent;
	}

	public function イベントを変更する(
			$title,
			$memo,
			$startDateTime,
			$endDateTime = ''
	)
	{
		return $this->updateEvent($title, $memo, $startDateTime,$endDateTime);
	}
	/**
	 * イベントを変更する
	 * @param unknown $title
	 * @param unknown $memo
	 * @param unknown $startDateTime
	 * @param string $endDateTime
	 */
	public function updateEvent(
			$title,
			$memo,
			$startDateTime,
			$endDateTime = ''
	){
		/*ANALYZE*/$this->_outAnalyzer('start Google_Calender::updateEvent');
		if ($endDateTime == '') {
			$dateTime = strtotime($startDateTime) + self::デフォルト期間;
			$endDateTime = date('Y-m-d H:00', $dateTime);
		}
		$this->_targetEvent->title = $this->_service->newTitle($title);
		$this->_targetEvent->content = $this->_service->newContent($memo);;
		$when = $this->_createWhen($startDateTime,$endDateTime);
		$this->_targetEvent->when = array($when);
		try {
			/*ANALYZE*/$this->_outAnalyzer(print_r($this->_targetEvent, true));
			$this->_targetEvent->save();
		} catch (Zend_Gdata_App_Exception $e) {
			$this->exceptionErrorMessage = $e->getMessage();
			/*ANALYZE*/$this->_outAnalyzer($this->exceptionErrorMessage);
			return FALSE;
		}
		/*** ターゲットイベントバッファ初期化 */
		$this->_targetEvent = FALSE;
		return TRUE;
	}

	public function 更新ターゲットイベントを返す()
	{
		return $this->getTargetEvent();
	}
	/**
	 * 更新ターゲットイベントを返す
	 * @return boolean
	 */
	public function getTargetEvent()
	{
		return $this->_targetEvent;
	}

	static public function validDateTime($src)
	{
		$divide = explode(' ', $src);
		switch (count($divide)) {
			case 1:
				$date = $divide[0];
				$time = '00:00';
				break;
			case 2:
				$date = $divide[0];
				$time = $divide[1];
				break;
			default:
				return FALSE;
		}
		$divide = explode('-', $date);
		if (count($divide) != 3) {
			return FALSE;
		}
		$year = $divide[0];
		$month = $divide[1];
		$day = $divide[2];
		$divide = explode(':', $time);
		if (count($divide) != 2) {
			return FALSE;
		}
		$hour = $divide[0];
		$minute = $divide[1];
		if (!checkdate($month, $day, $year)) {
			return FALSE;
		}
		if (!is_numeric($hour)){
			return FALSE;
		}
		if ($hour > 23) {
			return FALSE;
		}
		if (!is_numeric($minute)) {
			return FALSE;
		}
		if ($minute > 59) {
			return FALSE;
		}
		return TRUE;
	}
	public function testval($src)
	{
		return $this->_validDateTime($src);
	}

	public function カレンダー一覧を返す()
	{
		return $this->getCalendarList();
	}
	/**
	 * カレンダー一覧を返す
	 * @return unknown
	 */
	public function getCalendarList()
	{
		$service = $this->_service;
		$listFeed= $service->getCalendarListFeed();
		$this->_calendarList = $listFeed;
		return $listFeed;
	}

	public function 登録カレンダー数を返す()
	{
		return $this->getCalendarCount();
	}
	/**
	 * 登録カレンダー数を返す
	 */
	public function getCalendarCount()
	{
		return count($this->_calendarList);
	}

	public function イベント一覧を返す($updatedMin)
	{
		return $this->getEventList($updatedMin);
	}
	/**
	 * イベント一覧を返す
	 * @param $updatedMin 更新日 '2013-11-23T04:09:14'
	 * @return boolean|unknown
	 */
	public function getEventList($updatedMin)
	{
		/*ANALYZE*/$this->_outAnalyzer('start Google_Calender::getEventList');
		$query = $this->_service->newEventQuery();
		$query->setUser($this->_user);
		$query->setVisibility('private');
		$query->setProjection('full');
		$query->setOrderby('starttime');

		/*** 更新日クエリー設置 */
		$query->setUpdatedMin($updatedMin);

//		$query->setParam('showDeleted', FALSE);

		// カレンダーサーバからイベントの一覧を取得します
		try {
			/*ANALYZE*/$this->_outAnalyzer(print_r($query,true));
			$eventFeed = $this->_service->getCalendarEventFeed($query);
		} catch (Zend_Gdata_App_Exception $e) {
			$this->exceptionErrorMessage = $e->getMessage();
			return FALSE;
		}
		$eventList = array();
		foreach ($eventFeed as $event) {
			$eventList[] = array(
				self::KEY_EVENT_ID => $event->id,
				self::KEY_EVENT_NAME => $event->title,
				self::KEY_EVENT_START_TIME => strtotime($event->when[0]->startTime),
				self::KEY_EVENT_END_TIME => strtotime($event->when[0]->endTime),
				self::KEY_EVENT_ALLDAY => self::isAlldayEvent($event),
				self::KEY_EVENT_UPDATED => $event->updated,
				self::KEY_EVENT_CONTENT => $event->content,
			);
		}
		/*ANALYZE*/$this->_outAnalyzer(print_r($eventList,true));
		$this->_eventFeed = $eventFeed;
		/*** 更新が削除のイベントを除外する*/
		$countEventList = count($eventList);
		$i = 0;
		while ($i < $countEventList) {
			$eventId = $eventList[$i][self::KEY_EVENT_ID];
			$result = $this->getEventFromId($eventId);
			if ($result === FALSE) {
				unset($eventList[$i]);
			}
			$i ++;
		}
		$eventList = array_merge($eventList);
		$this->_eventCount = count($eventList);
		/*ANALYZE*/$this->_outAnalyzer(print_r($eventList, true));
		return $eventList;
	}

	public function イベントIDからイベントを取得する($eventId)
	{
		return $this->getEventFromId($eventId);
	}
	/**
	 * イベントIDからイベントを取得する
	 * @param unknown $eventId
	 */
	public function getEventFromId($eventId)
	{
		/*ANALYZE*/$this->_outAnalyzer('start Google_Calender::getEventFromId');
		$sEventId = sprintf("%s", $eventId);
		try {
			/*ANALYZE*/$this->_outAnalyzer($sEventId);
			$event = $this->_service->getCalendarEventEntry($sEventId);
		} catch (Zend_Gdata_App_Exception $e) {
			$this->exceptionErrorMessage = $e->getMessage();
			/*ANALYZE*/$this->_outAnalyzer($this->exceptionErrorMessage, true);
			/*ANALYZE*/$this->_outAnalyzer('end Google_Calender::getEventFromId');
			return FALSE;
		}
		/*ANALYZE*/$this->_outAnalyzer('end Google_Calender::getEventFromId');
		return $event;
	}

	/**
	 * 終日イベントの場合、１を返す
	 * @param unknown $event
	 * @return number
	 */
	static public function isAlldayEvent($event)
	{
		$startTime = $event->when[0]->startTime;
		if (strlen($startTime) == strlen('2013-11-24')) {
			return 0;
		}
		return 1;
	}

	public function 対象カレンダー名を指定する($name)
	{
		return $this->selectCalendarByName($name);
	}
	public function selectCalendarByName($name)
	{
		/*** ユーザーカレンダーリストが未設定の場合、再取得を試みる */
		if (count($this->_calendarList) == 0) {
			$this->getCalendarList();
		}
		$index = 0;
		$calendarList = $this->_calendarList;
		foreach ($calendarList as $calendar) {
			if ($calendar->title == $name) {
				break;
			}
			$index ++;
		}
		if ($index == count($calendarList)) {
			return FALSE;
			$index = 0;
		}
		$result = $this->selectCalendarByIndex($index);
		return $result;
	}

	public function 対象カレンダー登録番号を指定する($index)
	{
		return $this->selectCalendarByIndex($index);
	}
	/**
	 * カレンダーを登録番号から指定する
	 * @param unknown $index
	 */
	public function selectCalendarByIndex($index)
	{
		/*** 登録カレンダーの数を超えていたら何もしない。*/
		if ($index >= count($this->_calendarList)) {
			return FALSE;
		}
		$this->_user = $this->_getUser($index);
		return TRUE;
	}

	public function カレンダー名を返す($index)
	{
		return $this->_getUser($index);
	}
	/**
	 * 登録カレンダーのUIDを返す
	 * @param unknown $index
	 */
	public function _getUser($index)
	{
		$user = $this->_user;
		$i = 0;
		foreach ($this->_calendarList as $calendar) {
			if ($i == $index) {
				// カレンダーリストのidの取得
				$listId = $calendar->id;
				// カレンダーのユーザー名取得
				$user = substr($listId, strrpos($listId, "/") + 1);
				break;
			}
			$i ++;
		}
		return $user;
	}

	public function getService()
	{
		return $this->_service;
	}

	public function 検索結果のイベント数を返す()
	{
		return $this->getEventCount();
	}
	public function getEventCount()
	{
		return $this->_eventCount;
	}

	/**
	 * 開始日時と終了日時（UNIXタイムスタンプ）から所要時間（分）を返す
	 * @param unknown $startUDate
	 * @param unknown $endUDate
	 * @return number
	 */
	public static function getTimeLength($startUDate, $endUDate)
	{
		$resultMinutes = 0;
		$uLength = $endUDate - $startUDate;
		$minutes = $uLength / 60;
		$resultMinutes = round($minutes);
		return $resultMinutes;
	}
	/**
	 * UNIXタイムスタンプからイベント開始終了日時文字列を返す
	 * 2013-11-24 20:00
	 * @param unknown $uTime
	 * @param string $allDayFlg
	 */
	public static function uTime2String($uTime, $allDayFlg=FALSE)
	{
		$sResult = date('Y-m-d', $uTime);
		if ($allDayFlg == FALSE) {
			$sResult .= ' ' . date('H:i', $uTime);
		}
		return $sResult;
	}

	protected function _outAnalyzer($data) {
		if (class_exists('analyzer')) {
			analyzer::saveLog('Calendar', date(DATE_ATOM) . "....\n" . $data . "\n......\n");
		}
	}
}

/**
 * 単体テストコードブロック
 */
if (PATH_SEPARATOR == ';') {


if (class_exists('UnitTestCase22')) {
	include_once 'simpletest/unit_tester.php';
	include_once 'simpletest/reporter.php';
class GoogleTest extends UnitTestCase
{
	protected $_googleCalendar;
	protected $_userCalender;

	public function setUp()
	{
		$up = file(dirname(__FILE__). '/password.txt', FILE_IGNORE_NEW_LINES);
		$user = $up[0];
		$password = $up[1];
		$this->_userCalender = $up[2];
		$this->_googleCalendar = new Google_Calender($user, $password);
		$this->_googleCalendar->getCalendarList();
	}

	public function test1200()
	{
		$eventId = 'http://www.google.com/calendar/feeds/0rhh763d7t49tfnn28bgkuj5lg%40group.calendar.google.com/private/full/qmtom3s97mo1gc0j6a68j78l2c';
		$this->_googleCalendar->setTargetEvent($eventId);
		$this->_googleCalendar->updateEvent(
				'タイトル替えちゃったyo',
				'メモも買えちゃったyo',
				'2013-12-28 13:00',
				'2013-12-28 14:00'
		);
		echo "test end ...\n";
	}

	public function test1300()
	{
		$this->_googleCalendar->selectCalendarByName($this->_userCalender);
		$id = (string)$this->_googleCalendar->addEvent('いい感じ', 'これでいけるか', '2014-01-01 20:00', '2014-01-01 21:00');
//		$this->_googleCalendar->addEvent('終日だね', 'これでいけるか', '2013-11-24');
	}

	public function test1110()
	{
		$s = Google_Calender::uTime2String(time(), TRUE);
		echo $s . "\n";
	}

	public function test1100()
	{
		$ret = Google_Calender::validDateTime('2012-01-01 00:00');
		$this->assertTrue($ret,'ok min');
		$ret = Google_Calender::validDateTime('2012-12-31 23:59');
		$this->assertTrue($ret, 'ok max');
		$ret = Google_Calender::validDateTime('2012-12-31');
		$this->assertTrue($ret, 'ok only day');
		$ret = Google_Calender::validDateTime('2012.12.11 11:30');
		$this->assertFalse($ret, 'err format');
		$ret = Google_Calender::validDateTime('2012-13-31 23:59');
		$this->assertFalse($ret, 'over month');
		$ret = Google_Calender::validDateTime('2012-12-31 24:00');
		$this->assertFalse($ret, 'over hour');
		$ret = Google_Calender::validDateTime('2012-12-31 23:60');
		$this->assertFalse($ret, 'over minute');

		$obj = $this->_googleCalendar;
		$calendarList = $obj->getCalendarList();
		echo count($calendarList) . "\n";
		foreach ($calendarList as $calendar) {
			echo $calendar->title . "\n";
		}

		$obj->selectCalendarByName($this->_userCalender);
		$eventList = $obj->getEventList('2013-12-28T04:09:14');
		foreach ($eventList as $event) {
			echo 'title   : ' . $event[Google_Calender::KEY_EVENT_NAME] . "\n";
			echo 'start   : ' . date('Y.m.d H:i',$event[Google_Calender::KEY_EVENT_START_TIME])."\n";
			echo 'end     : ' . date('Y.m.d H:i',$event[Google_Calender::KEY_EVENT_END_TIME]). "\n";
			echo 'id      : ' . $event[Google_Calender::KEY_EVENT_ID]. "\n";
			echo 'allday  : ' . $event[Google_Calender::KEY_EVENT_ALLDAY] . "\n";
			echo 'updated : ' . $event[Google_Calender::KEY_EVENT_UPDATED] . "\n";
			echo "****DUMP****\n";
			//print_r($event);
			echo "***END DUMP****\n";
		}
		echo 'event count : ' . $obj->getEventCount() . "\n";
		echo 'calender count : ' . $obj->getCalendarCount() . "\n";
		echo 'user : ' . $obj->_getUser(0);

	}
}
}
}